package com.sneakxy.cloudbase.platform.service;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Calendar;
import java.util.UUID;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.csource.common.MyException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.sneakxy.cloudbase.platform.bean.UploadFile;
import com.sneakxy.cloudbase.platform.bean.dto.UploadFileDTO;
import com.sneakxy.cloudbase.platform.repository.UploadFileRepository;
import com.sneakxy.cloudbase.platform.utils.FtpClient;
import com.sneakxy.cloudbase.platform.utils.FtpClientFactory;
import com.sneakxy.cloudbase.platform.utils.fastdfs.FastDfsClient;

/**
 * 
 * @author 潜行的青衣
 * @see
 */
@Service
public class UploadFileService extends BaseService<UploadFile, String, UploadFileRepository> implements IUploadFileService {

	private Logger log = LoggerFactory.getLogger(getClass());
	
	@Value("${merge.size.filetable}")
	private int mergeSize;
	
	@Autowired
	private FtpClientFactory ftpClientFactory;

	@Autowired
	private FastDfsClient fastDfsClient;
	
	@Value("${local.path}")
	private String localPath;
	
	@Override
	public String getTableName(String id) {
		return this.getTableName(id, mergeSize);
	}

	@Override
	public UploadFile findOne(String id) {
		return findOne(id, getTableName(id));
	}

	@Override
	public <S extends UploadFile> S save(S entity) {
		return save(entity, getTableName(entity.getId()));
	}

	@Override
	public void remove(String id) throws IOException, MyException {
		String tableName = getTableName(id);
		UploadFile file = findOne(id, tableName);
		if(StringUtils.equals(UploadFileDTO.TYPE_FTP, file.getStoretype())) {
			FtpClient ftpClient = ftpClientFactory.getObject();
			try {
				ftpClient.login();
				ftpClient.remove(file.getPath());
			} finally {
				ftpClient.close();
			}
		} else if(StringUtils.equals(UploadFileDTO.TYPE_FASTDFS, file.getStoretype())) {
			this.fastDfsClient.deleteFile(file.getPath());
		} else if(StringUtils.equals(UploadFileDTO.TYPE_LOCAL, file.getStoretype())) {
			String basePath = StringUtils.endsWith(localPath, File.separator) ? localPath : StringUtils.join(localPath, File.separator);
			Files.deleteIfExists(Paths.get(basePath, file.getPath()));
		}
		delete(id, tableName);
	}

	@Override
	public String storeToFastDfs(MultipartFile file) throws IOException, MyException {
		return this.fastDfsClient.uploadFile(file.getInputStream(), file.getSize(), "");
	}

	@Override
	public String storeToFastDfs(InputStream is, int size) throws IOException, MyException {
		return this.fastDfsClient.uploadFile(is, size, "");
	}

	@Override
	public String storeToFtp(MultipartFile file, String account) throws IOException {
		return storeToFtp(file.getInputStream(), account);
	}

	@Override
	public String storeToFtp(InputStream is, String account) throws IOException {
		String path = StringUtils.join(File.separator, this.buildPath(account));
		String name = buildFileName();
		FtpClient ftpClient = ftpClientFactory.getObject();
		try {
			ftpClient.login();
			ftpClient.upload(path, name, is);
			return StringUtils.join(path, name);
		} catch (IOException e) {
			log.error("ftp上传失败.", e);
			throw new IOException("ftp上传失败.");
		} finally {
			ftpClient.close();
		}
	}

	public String buildPath(String account) {
		final String formatter = "yyyyMMdd";
		return StringUtils.join(
				"upload", File.separator, 
				account, File.separator, 
				DateFormatUtils.format(Calendar.getInstance(), formatter), File.separator);
	}
	
	public String buildFileName() {
		return UUID.randomUUID().toString();
	}
	
	@Override
	public String storeToLocal(MultipartFile file, String account) throws IOException {
		return storeToLocal(file.getInputStream(), account);
	}

	@Override
	public String storeToLocal(InputStream is, String account) throws IOException {
		String basePath = StringUtils.endsWith(localPath, File.separator) ? localPath : StringUtils.join(localPath, File.separator);
		String path = this.buildPath(account);
		String name = buildFileName();
		String folder = StringUtils.join(basePath, path);
		File dir = new File(folder);
		if(!dir.exists()) {
			dir.mkdirs();
		}
		
		try(OutputStream os = new FileOutputStream(StringUtils.join(folder, name))) {
			IOUtils.copy(is, os);
		}
		return StringUtils.join(path, name);
	}

}
